// START
/**
 * @author: earcam
 * @since: 2010-06-24 02:30:33 BST
 */
;
/**
  * namespace jqt
  */
var jqt = {

	VERTICAL: {"TOP":"top", "MIDDLE":"middle", "BOTTOM":"bottom"},
	HORIZONTAL: {"LEFT":"left", "CENTER":"center", "RIGHT":"right"},
	SORT_DIRECTION: {"ASCENDING":"ASC", "DESCENDING":"DESC"},

	/**
	  * jqt.Align
	  * vertical: enum @see jqt.VERTICAL
	  * horizontal: enum @see jqt.HORIZONTAL
	  */
	Align: function(horizontal, vertical){
		this.vertical = vertical;
		this.horizontal = horizontal;
	},


	/**
	  * jqt.SortOrder
	  * active: boolean
	  * direction: @see jqt.SORT_DIRECTION enum
	  * index: position, relative to other column's jqt.SortOrders
	  */
	SortOrder: function(active, direction, index){
		this.active = active;
		this.direction = direction;
		this.index;
	},


	Pager: function(first, size){
		this.first = first;
		this.size = size;
	},

	/**
	  * namespace: jqt.model
	  */
	model : {
		/**
		  * jqt.model.Column
		  * title: "Column Heading"
		  * fieldName: "name" used for data requests (db/object field)
		  * type: String|Date|Number|Boolean
		  * sortOrder: null || @see jqt.SortOrder
		  * filter: null || @see jqt.Filter
		  * align: null || {title = @see jqt.Align, data = @see jqt.Align} 
		  */
		Column: function(title, fieldName, type, sortOrder, filter, align) {
			this.title = title;  
			this.fieldName = fieldName;
			this.type = type;
			this.align = align;
			this.sortOrder = (sortOrder === null || sortOrder == false) ? new jqt.SortOrder(false) : sortOrder
			this.filter= null; //null|{active:true|false,operator:"enum",value:"String"} } //TODO define Operator enum & Filter object
		}
	},


	/**
	  * namespace: jqt.controller
	  */
	controller: {
		/**
		  * jqt.controller.LocalDataHandler
		  *
		  * pager: @see jqt.Pager
		  */
		LocalDataHandler: function(pager){
			this.data = null; //array of arrays of primitives
			this.columns = null; //Column[]
			this.pager = pager;
			this.total = 0;
		},
		/**
		  * jqt.controller.AjaxDataHandler
		  *
		  * pager: @see jqt.Pager
		  */
		AjaxDataHandler: function(baseUrl, pager){
			this.data = null; //array of arrays of primitives
			this.columns = null; //Column[]
			this.pager = pager;
			this.total = 0;
			this.baseUrl = baseUrl;
		}
	},


	/**
	  * namespace: jqt.view
	  *
	  */
	view:  {
		/**
		  * jqt.view.Header
		  *
		  */
		Header: function(parent, dataHandler) {
			this.parentId = parent.attr("id");
			this.parent = parent;
			this.dataHandler = dataHandler;
			this.thead = null;
			this.menu = null;
		},

		/**
		  * jqt.view.Body
		  *
		  */
		Body: function(parent) {
			this.parentId = parent.attr("id");
			this.parent = parent;
			this.tbody = null;
		},
		/**
		  * jqt.view.Footer
		  *
		  */
		Footer: function(parent) {
			this.parentId = parent.attr("id");
			this.parent = parent;
			this.tfooter = null;
		}
	},

	
	/**
	  * jqt.Table
	  *
	  */
	Table: function(id, dataHandler) {
		if(id == null || id == undefined){
			throw {"msg": "No ID parameter in constructor call"};
		}
		this.container = jQuery(id);
		this.dataHandler = dataHandler;
		this.table = jQuery("<table class=\"ui-widget-content ui-corner-all\" id=\"" + this.container.attr("id") + "-table\"></table>");
		this.header = new jqt.view.Header(this.table, this.dataHandler);
		this.body = new jqt.view.Body(this.table);
		this.footer = new jqt.view.Footer(this.table);

		return this;
	}


};

jqt.Align.prototype = {
	getVertical: function(){
		return this.vertical;
	},
	getHorizontal: function(){
		return this.horizontal;
	},
	toString: function(){
		return "{horizontal: \"" + this.horizontal + "\", vertical:\"" + this.vertical + "\"}";
	}
};



jqt.model.Column.prototype = {
	getTitle: function(){ return title; },
	getFieldName: function(){ return fieldName; },
	getType: function(){ return type; },
	getAlign: function(){ return align; },
	getSortOrder: function(){ return sortOrder; },
	getFilter: function(){ return filter; },

	setAlign: function(align){ this.align = align; },
	setSortOrder: function(sortOrder){ this.sortOrder = sortOrder; },
	setFilter: function(filter){ this.filter = filter; }
};


jqt.SortOrder.prototype = {
	getActive: function(){ return this.active; },
	getDirection: function(){ return this.direction; },
	getIndex: function(){ return this.index; },

	setActive: function(active){ this.active = active; },
	setDirection: function(direction){ this.direction = direction; },
	setIndex: function(index){ this.index = index; }
};


jqt.controller.LocalDataHandler.prototype = {
	getData: function(){
		return this.data;
	},
	getColumns: function(){
		return this.columns;
	},
	getPager: function(){
		return this.pager; //TODO
	},
	load: function(){
		this.columns = [
			new jqt.model.Column("Name", "name", String, null, null, {title: new jqt.Align(jqt.HORIZONTAL.LEFT, jqt.HORIZONTAL.TOP), data: new jqt.Align(jqt.HORIZONTAL.LEFT, jqt.HORIZONTAL.TOP)}),
			new jqt.model.Column("Rank", "rank", Number, new jqt.SortOrder(true, jqt.SORT_DIRECTION.ASCENDING, 0), null, {title: new jqt.Align(jqt.HORIZONTAL.CENTER, jqt.HORIZONTAL.TOP), data: new jqt.Align(jqt.HORIZONTAL.CENTER, jqt.HORIZONTAL.TOP)}),
			new jqt.model.Column("Date", "date", Date, new jqt.SortOrder(false), null, null)
		];
		this.data = [
			["Aaaa", 50, new Date(2000, 6, 24, 02, 30, 0, 003)],
			["Aaaa", 60, new Date(2003, 6, 24, 02, 30, 0, 002)],
			["Aaaa", 70, new Date(2005, 6, 24, 02, 30, 0, 001)],

			["Bbbb", 60, new Date(2000, 6, 24, 02, 30, 0, 003)],
			["Bbbb", 70, new Date(2006, 6, 24, 02, 30, 0, 002)],
			["Bbbb", 80, new Date(2005, 6, 21, 02, 30, 0, 001)],

			["Cccc", 40, new Date(2000, 6, 24, 02, 30, 0, 003)],
			["Cccc", 91, new Date(2006, 6, 24, 02, 30, 0, 002)],
			["Cccc", 78, new Date(2005, 6, 24, 01, 55, 0, 000)],

			["Dddd", 20, new Date(2000, 6, 24, 03, 30, 0, 003)],
			["Dddd", 31, new Date(2001, 6, 24, 02, 30, 0, 002)]
		];
		this.total = 11;
		this.pager = new jqt.Pager(0, 20);
	},
	update: function(){
		var columns = this.columns, requestString = "[";
		for(i in columns){
			if(requestString !== "["){
				requestString += ",";
			}
			//TODO this ignores position
			if(columns[i].sortOrder !== null && columns[i].sortOrder.active === true){
				requestString += "{ property:\"" + columns[i].fieldName + "\",orderBy:\""+columns[i].sortOrder.direction+"\"}";
			}
			
		}
		requestString = " {sortOrder: " + requestString + "], pager: ";
		if(this.pager === null){
			requestString += "null";
		}else{
			requestString += "{first: " + this.pager.first + ", size: " + this.pager.size + "}";
		}
		requestString += "}";
console.log("requestString: " + requestString);
		return requestString;
	}
};

jqt.controller.AjaxDataHandler.prototype = {
	getData: function(){
		return this.data;
	},
	getColumns: function(){
		return this.columns;
	},
	getPager: function(){
		return this.pager; //TODO
	},
	load: function(){
		var thiz = this;
		console.log(this.baseUrl+this.update());
		
		jQuery.ajax({ url: this.baseUrl+this.update(), async: false, type:"json",
			success: function(data, textStatus, XMLHttpRequest){ 
				console.log(data);
				thiz.columns = data.columns; thiz.data = data.data; thiz.pager = data.pager; thiz.total = data.total; 
			},complete: function(xhr, textStatus){ console.log("feck: " + textStatus); }
		});

	},
	update: function(){
		var columns = this.columns, requestString = "[";
		for(i in columns){
			if(requestString !== "["){
				requestString += ",";
			}
			//TODO this ignores position
			if(columns[i].sortOrder !== null && columns[i].sortOrder.active === true){
				requestString += "{ property:\"" + columns[i].fieldName + "\",orderBy:\""+columns[i].sortOrder.direction+"\"}";
			}
		}
		requestString = "{\"sortOrders\":" + requestString + "], \"pager\":";
		if(this.pager === null){
			requestString += "null";
		}else{
			requestString += "{\"first\": " + this.pager.first + ", \"size\": " + this.pager.size + "}";
		}
		requestString += "}";
console.log("requestString: " + requestString);
		return requestString;
	}
};

jqt.view.Header.prototype = {
	draw: function(columns){
		console.log("jqt.view.Header.draw(): " + "#" + this.parent.attr("id") + "-thead");

		var thiz = this, 
			iconNS = "ui-icon-carat-2-n-s", iconN = "ui-icon-carat-1-n", iconS = "ui-icon-carat-1-s";

		this.menu = jQuery("<div class=\"ui-widget-content ui-corner-all\" id=\"" + 
				this.parent.attr("id") + "-thead-menu\" style=\"position:absolute;font-size:smaller;padding:5px\"></div>");
		this.parent.parent().prepend(this.menu);
		this.thead = jQuery("<thead id=\"" + this.parent.attr("id") + "-thead\"></thead>");
		for(i in columns){
			//console.log("columns["+i+"]: " + columns[i]);
			th = jQuery("<th></th>");
			th.addClass("ui-widget-header ui-corner-all");
			if(!(columns[i].align == undefined || columns[i].align.title === null)){
				th.css('text-align', columns[i].align.title.getHorizontal());
			}

			if(columns[i].sort !== null || columns[i].filter !== null){
				th.css("cursor", "pointer");
				th.bind("click", function(e){ thiz.choiceMenu(jQuery(this).index()); });
			}
			th.append(columns[i].title);
			this.thead.append(th);
		}
		this.thead.appendTo(this.parent);
	},
	choiceMenu: function(index){

		var thiz = this,
			column = this.dataHandler.getColumns()[index], 
			th = this.thead.find("th:eq("+index+")"), 
			pos = th.position(), direction = (column.sortOrder.active) ? column.sortOrder.direction : "n/a";

		this.menu.empty().append("<br/>");
		this.menu.css("left", pos.left);
		this.menu.css("top", pos.top + th.height());
	
		var sortBody = jQuery("<ul style=\"list-style-type:circle;margin-top:0\"></ul>"),
			cancel = jQuery("<span style=\"float:right;cursor:pointer\">cancel</span>").bind('click', function(e){ thiz.menu.hide(); }),
			asc = jQuery("<li style=\"cursor:pointer\">ascending</li>"),
			desc = jQuery("<li style=\"cursor:pointer\">descending</li>"),
			none = jQuery("<li style=\"cursor:pointer\">none</li>");

		if(column.sortOrder !== null){
			this.menu.append("<b>sort</b>");
			asc.bind('click', function(e){ column.sortOrder.active = true; column.sortOrder.direction = "ASC"; thiz.menu.hide(); thiz.dataHandler.update(); });
	//		asc.hoover(function(){}, function(){});
			asc.appendTo(sortBody);
			desc.bind('click', function(e){ column.sortOrder.active = true; column.sortOrder.direction = "DESC"; thiz.menu.hide(); thiz.dataHandler.update(); })
			desc.appendTo(sortBody);
			none.bind('click', function(e){ column.sortOrder.active = false; column.sortOrder.direction = ""; thiz.menu.hide(); });
			none.appendTo(sortBody);
			switch(direction){
				case 'ASC': asc.css("list-style-type", "disc"); 
					asc.unbind("click");
					asc.css("cursor", "default");
					break;
				case 'DESC': desc.css("list-style-type", "disc"); 
					desc.unbind("click");
					desc.css("cursor", "default");
					break;
				default: none.css("list-style-type", "disc"); 
					none.css("cursor", "default");
					none.unbind("click");
					break;
			}
			this.menu.append(sortBody);
		}
		if(column.filter !== null){
			this.menu.append("<b>filter</b>");
		}
		this.menu.append("<hr/>");
		this.menu.append(cancel);
		this.menu.show();
	}
};


jqt.view.Body.prototype = {
	draw: function(columns, data){
		console.log("jqt.view.Body.draw()");

	var i, j, row, cell;
	this.tbody = jQuery("<tbody></tbody>");
	for(i  in data){
		row = jQuery("<tr></tr>");
		for(j in columns){
			//refactor in cell renderers
			cell = jQuery("<td>"+data[i][j]+"</td>");
			if(!(columns[j].align == undefined || columns[j].align.data === null)){
				cell.css('text-align', columns[j].align.data.getHorizontal());
			}
			row.append(cell);
//// editable - TODO
//			cell.attr("contenteditable", true);
			cell.bind("focus", function(e){ 
				console.log("saving original: " + jQuery(this).html());
				jQuery.data(this, 'jqtabula.original', jQuery(this).html());
			});
			cell.bind("blur", function(e){
				console.log("new: " + jQuery(this).html());
				console.log("original: " + jQuery.data(this, 'jqtabula.original'));
				if(jQuery(this).html() == jQuery.data(this, 'jqtabula.original')){ 
					alert("No change");
				}else{ alert("Changed!"); }
			});
//// editable - TODO
		}
		this.tbody.append(row);
	}
	this.tbody.appendTo(this.parent);
	}
};


jqt.view.Footer.prototype = {
	draw: function(){
		console.log("jqt.view.Footer.draw()");
	}
};


jqt.Table.prototype = {
	load: function(){
		console.log("jqt.view.Table.load()");
		this.dataHandler.load();
	},
	draw: function(){
		console.log("jqt.view.Table.draw()");
		this.table.appendTo(this.container);
		this.header.draw(this.dataHandler.getColumns());
		this.body.draw(this.dataHandler.getColumns(), this.dataHandler.getData());
		this.footer.draw();
	}
};

